home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclUtil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  73.7 KB  |  2,808 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclUtil.c --
  3.  *
  4.  *    This file contains utility procedures that are used by many Tcl
  5.  *    commands.
  6.  *
  7.  * Copyright (c) 1987-1993 The Regents of the University of California.
  8.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tclUtil.c 1.161 97/08/12 17:07:18
  14.  */
  15.  
  16. #include "tclInt.h"
  17. #include "tclPort.h"
  18.  
  19. /*
  20.  * The following values are used in the flags returned by Tcl_ScanElement
  21.  * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
  22.  * defined in tcl.h;  make sure its value doesn't overlap with any of the
  23.  * values below.
  24.  *
  25.  * TCL_DONT_USE_BRACES -    1 means the string mustn't be enclosed in
  26.  *                braces (e.g. it contains unmatched braces,
  27.  *                or ends in a backslash character, or user
  28.  *                just doesn't want braces);  handle all
  29.  *                special characters by adding backslashes.
  30.  * USE_BRACES -            1 means the string contains a special
  31.  *                character that can be handled simply by
  32.  *                enclosing the entire argument in braces.
  33.  * BRACES_UNMATCHED -        1 means that braces aren't properly matched
  34.  *                in the argument.
  35.  */
  36.  
  37. #define USE_BRACES        2
  38. #define BRACES_UNMATCHED    4
  39.  
  40. /*
  41.  * The following values determine the precision used when converting
  42.  * floating-point values to strings.  This information is linked to all
  43.  * of the tcl_precision variables in all interpreters via the procedure
  44.  * TclPrecTraceProc.
  45.  *
  46.  * NOTE: these variables are not thread-safe.
  47.  */
  48.  
  49. static char precisionString[10] = "12";
  50.                 /* The string value of all the tcl_precision
  51.                  * variables. */
  52. static char precisionFormat[10] = "%.12g";
  53.                 /* The format string actually used in calls
  54.                  * to sprintf. */
  55.  
  56.  
  57. /*
  58.  * Function prototypes for local procedures in this file:
  59.  */
  60.  
  61. static void        SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
  62.                 int newSpace));
  63.  
  64. /*
  65.  *----------------------------------------------------------------------
  66.  *
  67.  * TclFindElement --
  68.  *
  69.  *    Given a pointer into a Tcl list, locate the first (or next)
  70.  *    element in the list.
  71.  *
  72.  * Results:
  73.  *    The return value is normally TCL_OK, which means that the
  74.  *    element was successfully located.  If TCL_ERROR is returned
  75.  *    it means that list didn't have proper list structure;
  76.  *    interp->result contains a more detailed error message.
  77.  *
  78.  *    If TCL_OK is returned, then *elementPtr will be set to point to the
  79.  *    first element of list, and *nextPtr will be set to point to the
  80.  *    character just after any white space following the last character
  81.  *    that's part of the element. If this is the last argument in the
  82.  *    list, then *nextPtr will point just after the last character in the
  83.  *    list (i.e., at the character at list+listLength). If sizePtr is
  84.  *    non-NULL, *sizePtr is filled in with the number of characters in the
  85.  *    element.  If the element is in braces, then *elementPtr will point
  86.  *    to the character after the opening brace and *sizePtr will not
  87.  *    include either of the braces. If there isn't an element in the list,
  88.  *    *sizePtr will be zero, and both *elementPtr and *termPtr will point
  89.  *    just after the last character in the list. Note: this procedure does
  90.  *    NOT collapse backslash sequences.
  91.  *
  92.  * Side effects:
  93.  *    None.
  94.  *
  95.  *----------------------------------------------------------------------
  96.  */
  97.  
  98. int
  99. TclFindElement(interp, list, listLength, elementPtr, nextPtr, sizePtr,
  100.            bracePtr)
  101.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. 
  102.                  * If NULL, then no error message is left
  103.                  * after errors. */
  104.     char *list;            /* Points to the first byte of a string
  105.                  * containing a Tcl list with zero or more
  106.                  * elements (possibly in braces). */
  107.     int listLength;        /* Number of bytes in the list's string. */
  108.     char **elementPtr;        /* Where to put address of first significant
  109.                  * character in first element of list. */
  110.     char **nextPtr;        /* Fill in with location of character just
  111.                  * after all white space following end of
  112.                  * argument (next arg or end of list). */
  113.     int *sizePtr;        /* If non-zero, fill in with size of
  114.                  * element. */
  115.     int *bracePtr;        /* If non-zero, fill in with non-zero/zero
  116.                  * to indicate that arg was/wasn't
  117.                  * in braces. */
  118. {
  119.     char *p = list;
  120.     char *elemStart;        /* Points to first byte of first element. */
  121.     char *limit;        /* Points just after list's last byte. */
  122.     int openBraces = 0;        /* Brace nesting level during parse. */
  123.     int inQuotes = 0;
  124.     int size = 0;        /* Init. avoids compiler warning. */
  125.     int numChars;
  126.     char *p2;
  127.     
  128.     /*
  129.      * Skim off leading white space and check for an opening brace or
  130.      * quote. We treat embedded NULLs in the list as bytes belonging to
  131.      * a list element. Note: use of "isascii" below and elsewhere in this
  132.      * procedure is a temporary hack (7/27/90) because Mx uses characters
  133.      * with the high-order bit set for some things. This should probably
  134.      * be changed back eventually, or all of Tcl should call isascii.
  135.      */
  136.  
  137.     limit = (list + listLength);
  138.     while ((p < limit) && (isspace(UCHAR(*p)))) {
  139.     p++;
  140.     }
  141.     if (p == limit) {        /* no element found */
  142.     elemStart = limit;
  143.     goto done;
  144.     }
  145.  
  146.     if (*p == '{') {
  147.     openBraces = 1;
  148.     p++;
  149.     } else if (*p == '"') {
  150.     inQuotes = 1;
  151.     p++;
  152.     }
  153.     elemStart = p;
  154.     if (bracePtr != 0) {
  155.     *bracePtr = openBraces;
  156.     }
  157.  
  158.     /*
  159.      * Find element's end (a space, close brace, or the end of the string).
  160.      */
  161.  
  162.     while (p < limit) {
  163.     switch (*p) {
  164.  
  165.         /*
  166.          * Open brace: don't treat specially unless the element is in
  167.          * braces. In this case, keep a nesting count.
  168.          */
  169.  
  170.         case '{':
  171.         if (openBraces != 0) {
  172.             openBraces++;
  173.         }
  174.         break;
  175.  
  176.         /*
  177.          * Close brace: if element is in braces, keep nesting count and
  178.          * quit when the last close brace is seen.
  179.          */
  180.  
  181.         case '}':
  182.         if (openBraces > 1) {
  183.             openBraces--;
  184.         } else if (openBraces == 1) {
  185.             size = (p - elemStart);
  186.             p++;
  187.             if ((p >= limit) || isspace(UCHAR(*p))) {
  188.             goto done;
  189.             }
  190.  
  191.             /*
  192.              * Garbage after the closing brace; return an error.
  193.              */
  194.             
  195.             if (interp != NULL) {
  196.             char buf[100];
  197.             
  198.             p2 = p;
  199.             while ((p2 < limit) && (!isspace(UCHAR(*p2)))
  200.                     && (p2 < p+20)) {
  201.                 p2++;
  202.             }
  203.             sprintf(buf,
  204.                 "list element in braces followed by \"%.*s\" instead of space",
  205.                 (int) (p2-p), p);
  206.             Tcl_SetResult(interp, buf, TCL_VOLATILE);
  207.             }
  208.             return TCL_ERROR;
  209.         }
  210.         break;
  211.  
  212.         /*
  213.          * Backslash:  skip over everything up to the end of the
  214.          * backslash sequence.
  215.          */
  216.  
  217.         case '\\': {
  218.         (void) Tcl_Backslash(p, &numChars);
  219.         p += (numChars - 1);
  220.         break;
  221.         }
  222.  
  223.         /*
  224.          * Space: ignore if element is in braces or quotes; otherwise
  225.          * terminate element.
  226.          */
  227.  
  228.         case ' ':
  229.         case '\f':
  230.         case '\n':
  231.         case '\r':
  232.         case '\t':
  233.         case '\v':
  234.         if ((openBraces == 0) && !inQuotes) {
  235.             size = (p - elemStart);
  236.             goto done;
  237.         }
  238.         break;
  239.  
  240.         /*
  241.          * Double-quote: if element is in quotes then terminate it.
  242.          */
  243.  
  244.         case '"':
  245.         if (inQuotes) {
  246.             size = (p - elemStart);
  247.             p++;
  248.             if ((p >= limit) || isspace(UCHAR(*p))) {
  249.             goto done;
  250.             }
  251.  
  252.             /*
  253.              * Garbage after the closing quote; return an error.
  254.              */
  255.             
  256.             if (interp != NULL) {
  257.             char buf[100];
  258.             
  259.             p2 = p;
  260.             while ((p2 < limit) && (!isspace(UCHAR(*p2)))
  261.                  && (p2 < p+20)) {
  262.                 p2++;
  263.             }
  264.             sprintf(buf,
  265.                 "list element in quotes followed by \"%.*s\" %s",
  266.                 (int) (p2-p), p, "instead of space");
  267.             Tcl_SetResult(interp, buf, TCL_VOLATILE);
  268.             }
  269.             return TCL_ERROR;
  270.         }
  271.         break;
  272.     }
  273.     p++;
  274.     }
  275.  
  276.  
  277.     /*
  278.      * End of list: terminate element.
  279.      */
  280.  
  281.     if (p == limit) {
  282.     if (openBraces != 0) {
  283.         if (interp != NULL) {
  284.         Tcl_SetResult(interp, "unmatched open brace in list",
  285.             TCL_STATIC);
  286.         }
  287.         return TCL_ERROR;
  288.     } else if (inQuotes) {
  289.         if (interp != NULL) {
  290.         Tcl_SetResult(interp, "unmatched open quote in list",
  291.             TCL_STATIC);
  292.         }
  293.         return TCL_ERROR;
  294.     }
  295.     size = (p - elemStart);
  296.     }
  297.  
  298.     done:
  299.     while ((p < limit) && (isspace(UCHAR(*p)))) {
  300.     p++;
  301.     }
  302.     *elementPtr = elemStart;
  303.     *nextPtr = p;
  304.     if (sizePtr != 0) {
  305.     *sizePtr = size;
  306.     }
  307.     return TCL_OK;
  308. }
  309.  
  310. /*
  311.  *----------------------------------------------------------------------
  312.  *
  313.  * TclCopyAndCollapse --
  314.  *
  315.  *    Copy a string and eliminate any backslashes that aren't in braces.
  316.  *
  317.  * Results:
  318.  *    There is no return value. Count characters get copied from src to
  319.  *    dst. Along the way, if backslash sequences are found outside braces,
  320.  *    the backslashes are eliminated in the copy. After scanning count
  321.  *    chars from source, a null character is placed at the end of dst.
  322.  *    Returns the number of characters that got copied.
  323.  *
  324.  * Side effects:
  325.  *    None.
  326.  *
  327.  *----------------------------------------------------------------------
  328.  */
  329.  
  330. int
  331. TclCopyAndCollapse(count, src, dst)
  332.     int count;            /* Number of characters to copy from src. */
  333.     char *src;            /* Copy from here... */
  334.     char *dst;            /* ... to here. */
  335. {
  336.     char c;
  337.     int numRead;
  338.     int newCount = 0;
  339.  
  340.     for (c = *src;  count > 0;  src++, c = *src, count--) {
  341.     if (c == '\\') {
  342.         *dst = Tcl_Backslash(src, &numRead);
  343.         dst++;
  344.         src += numRead-1;
  345.         count -= numRead-1;
  346.         newCount++;
  347.     } else {
  348.         *dst = c;
  349.         dst++;
  350.         newCount++;
  351.     }
  352.     }
  353.     *dst = 0;
  354.     return newCount;
  355. }
  356.  
  357. /*
  358.  *----------------------------------------------------------------------
  359.  *
  360.  * Tcl_SplitList --
  361.  *
  362.  *    Splits a list up into its constituent fields.
  363.  *
  364.  * Results
  365.  *    The return value is normally TCL_OK, which means that
  366.  *    the list was successfully split up.  If TCL_ERROR is
  367.  *    returned, it means that "list" didn't have proper list
  368.  *    structure;  interp->result will contain a more detailed
  369.  *    error message.
  370.  *
  371.  *    *argvPtr will be filled in with the address of an array
  372.  *    whose elements point to the elements of list, in order.
  373.  *    *argcPtr will get filled in with the number of valid elements
  374.  *    in the array.  A single block of memory is dynamically allocated
  375.  *    to hold both the argv array and a copy of the list (with
  376.  *    backslashes and braces removed in the standard way).
  377.  *    The caller must eventually free this memory by calling free()
  378.  *    on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
  379.  *    if the procedure returns normally.
  380.  *
  381.  * Side effects:
  382.  *    Memory is allocated.
  383.  *
  384.  *----------------------------------------------------------------------
  385.  */
  386.  
  387. int
  388. Tcl_SplitList(interp, list, argcPtr, argvPtr)
  389.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. 
  390.                  * If NULL, no error message is left. */
  391.     char *list;            /* Pointer to string with list structure. */
  392.     int *argcPtr;        /* Pointer to location to fill in with
  393.                  * the number of elements in the list. */
  394.     char ***argvPtr;        /* Pointer to place to store pointer to
  395.                  * array of pointers to list elements. */
  396. {
  397.     char **argv;
  398.     char *p;
  399.     int length, size, i, result, elSize, brace;
  400.     char *element;
  401.  
  402.     /*
  403.      * Figure out how much space to allocate.  There must be enough
  404.      * space for both the array of pointers and also for a copy of
  405.      * the list.  To estimate the number of pointers needed, count
  406.      * the number of space characters in the list.
  407.      */
  408.  
  409.     for (size = 1, p = list; *p != 0; p++) {
  410.     if (isspace(UCHAR(*p))) {
  411.         size++;
  412.     }
  413.     }
  414.     size++;            /* Leave space for final NULL pointer. */
  415.     argv = (char **) ckalloc((unsigned)
  416.         ((size * sizeof(char *)) + (p - list) + 1));
  417.     length = strlen(list);
  418.     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
  419.         *list != 0;  i++) {
  420.     char *prevList = list;
  421.     
  422.     result = TclFindElement(interp, list, length, &element,
  423.                 &list, &elSize, &brace);
  424.     length -= (list - prevList);
  425.     if (result != TCL_OK) {
  426.         ckfree((char *) argv);
  427.         return result;
  428.     }
  429.     if (*element == 0) {
  430.         break;
  431.     }
  432.     if (i >= size) {
  433.         ckfree((char *) argv);
  434.         if (interp != NULL) {
  435.         Tcl_SetResult(interp, "internal error in Tcl_SplitList",
  436.             TCL_STATIC);
  437.         }
  438.         return TCL_ERROR;
  439.     }
  440.     argv[i] = p;
  441.     if (brace) {
  442.         memcpy((VOID *) p, (VOID *) element, (size_t) elSize);
  443.         p += elSize;
  444.         *p = 0;
  445.         p++;
  446.     } else {
  447.         TclCopyAndCollapse(elSize, element, p);
  448.         p += elSize+1;
  449.     }
  450.     }
  451.  
  452.     argv[i] = NULL;
  453.     *argvPtr = argv;
  454.     *argcPtr = i;
  455.     return TCL_OK;
  456. }
  457.  
  458. /*
  459.  *----------------------------------------------------------------------
  460.  *
  461.  * Tcl_ScanElement --
  462.  *
  463.  *    This procedure is a companion procedure to Tcl_ConvertElement.
  464.  *    It scans a string to see what needs to be done to it (e.g. add
  465.  *    backslashes or enclosing braces) to make the string into a
  466.  *    valid Tcl list element.
  467.  *
  468.  * Results:
  469.  *    The return value is an overestimate of the number of characters
  470.  *    that will be needed by Tcl_ConvertElement to produce a valid
  471.  *    list element from string.  The word at *flagPtr is filled in
  472.  *    with a value needed by Tcl_ConvertElement when doing the actual
  473.  *    conversion.
  474.  *
  475.  * Side effects:
  476.  *    None.
  477.  *
  478.  *----------------------------------------------------------------------
  479.  */
  480.  
  481. int
  482. Tcl_ScanElement(string, flagPtr)
  483.     CONST char *string;        /* String to convert to Tcl list element. */
  484.     int *flagPtr;        /* Where to store information to guide
  485.                  * Tcl_ConvertCountedElement. */
  486. {
  487.     return Tcl_ScanCountedElement(string, -1, flagPtr);
  488. }
  489.  
  490. /*
  491.  *----------------------------------------------------------------------
  492.  *
  493.  * Tcl_ScanCountedElement --
  494.  *
  495.  *    This procedure is a companion procedure to
  496.  *    Tcl_ConvertCountedElement.  It scans a string to see what
  497.  *    needs to be done to it (e.g. add backslashes or enclosing
  498.  *    braces) to make the string into a valid Tcl list element.
  499.  *    If length is -1, then the string is scanned up to the first
  500.  *    null byte.
  501.  *
  502.  * Results:
  503.  *    The return value is an overestimate of the number of characters
  504.  *    that will be needed by Tcl_ConvertCountedElement to produce a
  505.  *    valid list element from string.  The word at *flagPtr is
  506.  *    filled in with a value needed by Tcl_ConvertCountedElement
  507.  *    when doing the actual conversion.
  508.  *
  509.  * Side effects:
  510.  *    None.
  511.  *
  512.  *----------------------------------------------------------------------
  513.  */
  514.  
  515. int
  516. Tcl_ScanCountedElement(string, length, flagPtr)
  517.     CONST char *string;        /* String to convert to Tcl list element. */
  518.     int length;            /* Number of bytes in string, or -1. */
  519.     int *flagPtr;        /* Where to store information to guide
  520.                  * Tcl_ConvertElement. */
  521. {
  522.     int flags, nestingLevel;
  523.     CONST char *p, *lastChar;
  524.  
  525.     /*
  526.      * This procedure and Tcl_ConvertElement together do two things:
  527.      *
  528.      * 1. They produce a proper list, one that will yield back the
  529.      * argument strings when evaluated or when disassembled with
  530.      * Tcl_SplitList.  This is the most important thing.
  531.      * 
  532.      * 2. They try to produce legible output, which means minimizing the
  533.      * use of backslashes (using braces instead).  However, there are
  534.      * some situations where backslashes must be used (e.g. an element
  535.      * like "{abc": the leading brace will have to be backslashed.
  536.      * For each element, one of three things must be done:
  537.      *
  538.      * (a) Use the element as-is (it doesn't contain any special
  539.      * characters).  This is the most desirable option.
  540.      *
  541.      * (b) Enclose the element in braces, but leave the contents alone.
  542.      * This happens if the element contains embedded space, or if it
  543.      * contains characters with special interpretation ($, [, ;, or \),
  544.      * or if it starts with a brace or double-quote, or if there are
  545.      * no characters in the element.
  546.      *
  547.      * (c) Don't enclose the element in braces, but add backslashes to
  548.      * prevent special interpretation of special characters.  This is a
  549.      * last resort used when the argument would normally fall under case
  550.      * (b) but contains unmatched braces.  It also occurs if the last
  551.      * character of the argument is a backslash or if the element contains
  552.      * a backslash followed by newline.
  553.      *
  554.      * The procedure figures out how many bytes will be needed to store
  555.      * the result (actually, it overestimates). It also collects information
  556.      * about the element in the form of a flags word.
  557.      *
  558.      * Note: list elements produced by this procedure and
  559.      * Tcl_ConvertCountedElement must have the property that they can be
  560.      * enclosing in curly braces to make sub-lists.  This means, for
  561.      * example, that we must not leave unmatched curly braces in the
  562.      * resulting list element.  This property is necessary in order for
  563.      * procedures like Tcl_DStringStartSublist to work.
  564.      */
  565.  
  566.     nestingLevel = 0;
  567.     flags = 0;
  568.     if (string == NULL) {
  569.     string = "";
  570.     }
  571.     if (length == -1) {
  572.     length = strlen(string);
  573.     }
  574.     lastChar = string + length;
  575.     p = string;
  576.     if ((p == lastChar) || (*p == '{') || (*p == '"')) {
  577.     flags |= USE_BRACES;
  578.     }
  579.     for ( ; p != lastChar; p++) {
  580.     switch (*p) {
  581.         case '{':
  582.         nestingLevel++;
  583.         break;
  584.         case '}':
  585.         nestingLevel--;
  586.         if (nestingLevel < 0) {
  587.             flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
  588.         }
  589.         break;
  590.         case '[':
  591.         case '$':
  592.         case ';':
  593.         case ' ':
  594.         case '\f':
  595.         case '\n':
  596.         case '\r':
  597.         case '\t':
  598.         case '\v':
  599.         flags |= USE_BRACES;
  600.         break;
  601.         case '\\':
  602.         if ((p+1 == lastChar) || (p[1] == '\n')) {
  603.             flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
  604.         } else {
  605.             int size;
  606.  
  607.             (void) Tcl_Backslash(p, &size);
  608.             p += size-1;
  609.             flags |= USE_BRACES;
  610.         }
  611.         break;
  612.     }
  613.     }
  614.     if (nestingLevel != 0) {
  615.     flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
  616.     }
  617.     *flagPtr = flags;
  618.  
  619.     /*
  620.      * Allow enough space to backslash every character plus leave
  621.      * two spaces for braces.
  622.      */
  623.  
  624.     return 2*(p-string) + 2;
  625. }
  626.  
  627. /*
  628.  *----------------------------------------------------------------------
  629.  *
  630.  * Tcl_ConvertElement --
  631.  *
  632.  *    This is a companion procedure to Tcl_ScanElement.  Given
  633.  *    the information produced by Tcl_ScanElement, this procedure
  634.  *    converts a string to a list element equal to that string.
  635.  *
  636.  * Results:
  637.  *    Information is copied to *dst in the form of a list element
  638.  *    identical to src (i.e. if Tcl_SplitList is applied to dst it
  639.  *    will produce a string identical to src).  The return value is
  640.  *    a count of the number of characters copied (not including the
  641.  *    terminating NULL character).
  642.  *
  643.  * Side effects:
  644.  *    None.
  645.  *
  646.  *----------------------------------------------------------------------
  647.  */
  648.  
  649. int
  650. Tcl_ConvertElement(src, dst, flags)
  651.     CONST char *src;        /* Source information for list element. */
  652.     char *dst;            /* Place to put list-ified element. */
  653.     int flags;            /* Flags produced by Tcl_ScanElement. */
  654. {
  655.     return Tcl_ConvertCountedElement(src, -1, dst, flags);
  656. }
  657.  
  658. /*
  659.  *----------------------------------------------------------------------
  660.  *
  661.  * Tcl_ConvertCountedElement --
  662.  *
  663.  *    This is a companion procedure to Tcl_ScanCountedElement.  Given
  664.  *    the information produced by Tcl_ScanCountedElement, this
  665.  *    procedure converts a string to a list element equal to that
  666.  *    string.
  667.  *
  668.  * Results:
  669.  *    Information is copied to *dst in the form of a list element
  670.  *    identical to src (i.e. if Tcl_SplitList is applied to dst it
  671.  *    will produce a string identical to src).  The return value is
  672.  *    a count of the number of characters copied (not including the
  673.  *    terminating NULL character).
  674.  *
  675.  * Side effects:
  676.  *    None.
  677.  *
  678.  *----------------------------------------------------------------------
  679.  */
  680.  
  681. int
  682. Tcl_ConvertCountedElement(src, length, dst, flags)
  683.     CONST char *src;        /* Source information for list element. */
  684.     int length;            /* Number of bytes in src, or -1. */
  685.     char *dst;            /* Place to put list-ified element. */
  686.     int flags;            /* Flags produced by Tcl_ScanElement. */
  687. {
  688.     char *p = dst;
  689.     CONST char *lastChar;
  690.  
  691.     /*
  692.      * See the comment block at the beginning of the Tcl_ScanElement
  693.      * code for details of how this works.
  694.      */
  695.  
  696.     if (src && length == -1) {
  697.     length = strlen(src);
  698.     }
  699.     if ((src == NULL) || (length == 0)) {
  700.     p[0] = '{';
  701.     p[1] = '}';
  702.     p[2] = 0;
  703.     return 2;
  704.     }
  705.     lastChar = src + length;
  706.     if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
  707.     *p = '{';
  708.     p++;
  709.     for ( ; src != lastChar; src++, p++) {
  710.         *p = *src;
  711.     }
  712.     *p = '}';
  713.     p++;
  714.     } else {
  715.     if (*src == '{') {
  716.         /*
  717.          * Can't have a leading brace unless the whole element is
  718.          * enclosed in braces.  Add a backslash before the brace.
  719.          * Furthermore, this may destroy the balance between open
  720.          * and close braces, so set BRACES_UNMATCHED.
  721.          */
  722.  
  723.         p[0] = '\\';
  724.         p[1] = '{';
  725.         p += 2;
  726.         src++;
  727.         flags |= BRACES_UNMATCHED;
  728.     }
  729.     for (; src != lastChar; src++) {
  730.         switch (*src) {
  731.         case ']':
  732.         case '[':
  733.         case '$':
  734.         case ';':
  735.         case ' ':
  736.         case '\\':
  737.         case '"':
  738.             *p = '\\';
  739.             p++;
  740.             break;
  741.         case '{':
  742.         case '}':
  743.             /*
  744.              * It may not seem necessary to backslash braces, but
  745.              * it is.  The reason for this is that the resulting
  746.              * list element may actually be an element of a sub-list
  747.              * enclosed in braces (e.g. if Tcl_DStringStartSublist
  748.              * has been invoked), so there may be a brace mismatch
  749.              * if the braces aren't backslashed.
  750.              */
  751.  
  752.             if (flags & BRACES_UNMATCHED) {
  753.             *p = '\\';
  754.             p++;
  755.             }
  756.             break;
  757.         case '\f':
  758.             *p = '\\';
  759.             p++;
  760.             *p = 'f';
  761.             p++;
  762.             continue;
  763.         case '\n':
  764.             *p = '\\';
  765.             p++;
  766.             *p = 'n';
  767.             p++;
  768.             continue;
  769.         case '\r':
  770.             *p = '\\';
  771.             p++;
  772.             *p = 'r';
  773.             p++;
  774.             continue;
  775.         case '\t':
  776.             *p = '\\';
  777.             p++;
  778.             *p = 't';
  779.             p++;
  780.             continue;
  781.         case '\v':
  782.             *p = '\\';
  783.             p++;
  784.             *p = 'v';
  785.             p++;
  786.             continue;
  787.         }
  788.         *p = *src;
  789.         p++;
  790.     }
  791.     }
  792.     *p = '\0';
  793.     return p-dst;
  794. }
  795.  
  796. /*
  797.  *----------------------------------------------------------------------
  798.  *
  799.  * Tcl_Merge --
  800.  *
  801.  *    Given a collection of strings, merge them together into a
  802.  *    single string that has proper Tcl list structured (i.e.
  803.  *    Tcl_SplitList may be used to retrieve strings equal to the
  804.  *    original elements, and Tcl_Eval will parse the string back
  805.  *    into its original elements).
  806.  *
  807.  * Results:
  808.  *    The return value is the address of a dynamically-allocated
  809.  *    string containing the merged list.
  810.  *
  811.  * Side effects:
  812.  *    None.
  813.  *
  814.  *----------------------------------------------------------------------
  815.  */
  816.  
  817. char *
  818. Tcl_Merge(argc, argv)
  819.     int argc;            /* How many strings to merge. */
  820.     char **argv;        /* Array of string values. */
  821. {
  822. #   define LOCAL_SIZE 20
  823.     int localFlags[LOCAL_SIZE], *flagPtr;
  824.     int numChars;
  825.     char *result;
  826.     char *dst;
  827.     int i;
  828.  
  829.     /*
  830.      * Pass 1: estimate space, gather flags.
  831.      */
  832.  
  833.     if (argc <= LOCAL_SIZE) {
  834.     flagPtr = localFlags;
  835.     } else {
  836.     flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
  837.     }
  838.     numChars = 1;
  839.     for (i = 0; i < argc; i++) {
  840.     numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
  841.     }
  842.  
  843.     /*
  844.      * Pass two: copy into the result area.
  845.      */
  846.  
  847.     result = (char *) ckalloc((unsigned) numChars);
  848.     dst = result;
  849.     for (i = 0; i < argc; i++) {
  850.     numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
  851.     dst += numChars;
  852.     *dst = ' ';
  853.     dst++;
  854.     }
  855.     if (dst == result) {
  856.     *dst = 0;
  857.     } else {
  858.     dst[-1] = 0;
  859.     }
  860.  
  861.     if (flagPtr != localFlags) {
  862.     ckfree((char *) flagPtr);
  863.     }
  864.     return result;
  865. }
  866.  
  867. /*
  868.  *----------------------------------------------------------------------
  869.  *
  870.  * Tcl_Concat --
  871.  *
  872.  *    Concatenate a set of strings into a single large string.
  873.  *
  874.  * Results:
  875.  *    The return value is dynamically-allocated string containing
  876.  *    a concatenation of all the strings in argv, with spaces between
  877.  *    the original argv elements.
  878.  *
  879.  * Side effects:
  880.  *    Memory is allocated for the result;  the caller is responsible
  881.  *    for freeing the memory.
  882.  *
  883.  *----------------------------------------------------------------------
  884.  */
  885.  
  886. char *
  887. Tcl_Concat(argc, argv)
  888.     int argc;            /* Number of strings to concatenate. */
  889.     char **argv;        /* Array of strings to concatenate. */
  890. {
  891.     int totalSize, i;
  892.     char *p;
  893.     char *result;
  894.  
  895.     for (totalSize = 1, i = 0; i < argc; i++) {
  896.     totalSize += strlen(argv[i]) + 1;
  897.     }
  898.     result = (char *) ckalloc((unsigned) totalSize);
  899.     if (argc == 0) {
  900.     *result = '\0';
  901.     return result;
  902.     }
  903.     for (p = result, i = 0; i < argc; i++) {
  904.     char *element;
  905.     int length;
  906.  
  907.     /*
  908.      * Clip white space off the front and back of the string
  909.      * to generate a neater result, and ignore any empty
  910.      * elements.
  911.      */
  912.  
  913.     element = argv[i];
  914.     while (isspace(UCHAR(*element))) {
  915.         element++;
  916.     }
  917.     for (length = strlen(element);
  918.         (length > 0) && (isspace(UCHAR(element[length-1])))
  919.         && ((length < 2) || (element[length-2] != '\\'));
  920.         length--) {
  921.         /* Null loop body. */
  922.     }
  923.     if (length == 0) {
  924.         continue;
  925.     }
  926.     memcpy((VOID *) p, (VOID *) element, (size_t) length);
  927.     p += length;
  928.     *p = ' ';
  929.     p++;
  930.     }
  931.     if (p != result) {
  932.     p[-1] = 0;
  933.     } else {
  934.     *p = 0;
  935.     }
  936.     return result;
  937. }
  938.  
  939. /*
  940.  *----------------------------------------------------------------------
  941.  *
  942.  * Tcl_ConcatObj --
  943.  *
  944.  *    Concatenate the strings from a set of objects into a single string
  945.  *    object with spaces between the original strings.
  946.  *
  947.  * Results:
  948.  *    The return value is a new string object containing a concatenation
  949.  *    of the strings in objv. Its ref count is zero.
  950.  *
  951.  * Side effects:
  952.  *    A new object is created.
  953.  *
  954.  *----------------------------------------------------------------------
  955.  */
  956.  
  957. Tcl_Obj *
  958. Tcl_ConcatObj(objc, objv)
  959.     int objc;            /* Number of objects to concatenate. */
  960.     Tcl_Obj *CONST objv[];    /* Array of objects to concatenate. */
  961. {
  962.     int allocSize, finalSize, length, elemLength, i;
  963.     char *p;
  964.     char *element;
  965.     char *concatStr;
  966.     Tcl_Obj *objPtr;
  967.  
  968.     allocSize = 0;
  969.     for (i = 0;  i < objc;  i++) {
  970.     objPtr = objv[i];
  971.     element = TclGetStringFromObj(objPtr, &length);
  972.     if ((element != NULL) && (length > 0)) {
  973.         allocSize += (length + 1);
  974.     }
  975.     }
  976.     if (allocSize == 0) {
  977.     allocSize = 1;        /* enough for the NULL byte at end */
  978.     }
  979.  
  980.     /*
  981.      * Allocate storage for the concatenated result. Note that allocSize
  982.      * is one more than the total number of characters, and so includes
  983.      * room for the terminating NULL byte.
  984.      */
  985.     
  986.     concatStr = (char *) ckalloc((unsigned) allocSize);
  987.  
  988.     /*
  989.      * Now concatenate the elements. Clip white space off the front and back
  990.      * to generate a neater result, and ignore any empty elements. Also put
  991.      * a null byte at the end.
  992.      */
  993.  
  994.     finalSize = 0;
  995.     if (objc == 0) {
  996.     *concatStr = '\0';
  997.     } else {
  998.     p = concatStr;
  999.         for (i = 0;  i < objc;  i++) {
  1000.         objPtr = objv[i];
  1001.         element = TclGetStringFromObj(objPtr, &elemLength);
  1002.         while ((elemLength > 0) && (isspace(UCHAR(*element)))) {
  1003.              element++;
  1004.          elemLength--;
  1005.         }
  1006.  
  1007.         /*
  1008.          * Trim trailing white space.  But, be careful not to trim
  1009.          * a space character if it is preceded by a backslash: in
  1010.          * this case it could be significant.
  1011.          */
  1012.  
  1013.         while ((elemLength > 0)
  1014.             && isspace(UCHAR(element[elemLength-1]))
  1015.             && ((elemLength < 2) || (element[elemLength-2] != '\\'))) {
  1016.         elemLength--;
  1017.         }
  1018.         if (elemLength == 0) {
  1019.              continue;    /* nothing left of this element */
  1020.         }
  1021.         memcpy((VOID *) p, (VOID *) element, (size_t) elemLength);
  1022.         p += elemLength;
  1023.         *p = ' ';
  1024.         p++;
  1025.         finalSize += (elemLength + 1);
  1026.         }
  1027.         if (p != concatStr) {
  1028.         p[-1] = 0;
  1029.         finalSize -= 1;    /* we overwrote the final ' ' */
  1030.         } else {
  1031.         *p = 0;
  1032.         }
  1033.     }
  1034.     
  1035.     TclNewObj(objPtr);
  1036.     objPtr->bytes  = concatStr;
  1037.     objPtr->length = finalSize;
  1038.     return objPtr;
  1039. }
  1040.  
  1041. /*
  1042.  *----------------------------------------------------------------------
  1043.  *
  1044.  * Tcl_StringMatch --
  1045.  *
  1046.  *    See if a particular string matches a particular pattern.
  1047.  *
  1048.  * Results:
  1049.  *    The return value is 1 if string matches pattern, and
  1050.  *    0 otherwise.  The matching operation permits the following
  1051.  *    special characters in the pattern: *?\[] (see the manual
  1052.  *    entry for details on what these mean).
  1053.  *
  1054.  * Side effects:
  1055.  *    None.
  1056.  *
  1057.  *----------------------------------------------------------------------
  1058.  */
  1059.  
  1060. int
  1061. Tcl_StringMatch(string, pattern)
  1062.     char *string;        /* String. */
  1063.     char *pattern;        /* Pattern, which may contain special
  1064.                  * characters. */
  1065. {
  1066.     char c2;
  1067.  
  1068.     while (1) {
  1069.     /* See if we're at the end of both the pattern and the string.
  1070.      * If so, we succeeded.  If we're at the end of the pattern
  1071.      * but not at the end of the string, we failed.
  1072.      */
  1073.     
  1074.     if (*pattern == 0) {
  1075.         if (*string == 0) {
  1076.         return 1;
  1077.         } else {
  1078.         return 0;
  1079.         }
  1080.     }
  1081.     if ((*string == 0) && (*pattern != '*')) {
  1082.         return 0;
  1083.     }
  1084.  
  1085.     /* Check for a "*" as the next pattern character.  It matches
  1086.      * any substring.  We handle this by calling ourselves
  1087.      * recursively for each postfix of string, until either we
  1088.      * match or we reach the end of the string.
  1089.      */
  1090.     
  1091.     if (*pattern == '*') {
  1092.         pattern += 1;
  1093.         if (*pattern == 0) {
  1094.         return 1;
  1095.         }
  1096.         while (1) {
  1097.         if (Tcl_StringMatch(string, pattern)) {
  1098.             return 1;
  1099.         }
  1100.         if (*string == 0) {
  1101.             return 0;
  1102.         }
  1103.         string += 1;
  1104.         }
  1105.     }
  1106.     
  1107.     /* Check for a "?" as the next pattern character.  It matches
  1108.      * any single character.
  1109.      */
  1110.  
  1111.     if (*pattern == '?') {
  1112.         goto thisCharOK;
  1113.     }
  1114.  
  1115.     /* Check for a "[" as the next pattern character.  It is followed
  1116.      * by a list of characters that are acceptable, or by a range
  1117.      * (two characters separated by "-").
  1118.      */
  1119.     
  1120.     if (*pattern == '[') {
  1121.         pattern += 1;
  1122.         while (1) {
  1123.         if ((*pattern == ']') || (*pattern == 0)) {
  1124.             return 0;
  1125.         }
  1126.         if (*pattern == *string) {
  1127.             break;
  1128.         }
  1129.         if (pattern[1] == '-') {
  1130.             c2 = pattern[2];
  1131.             if (c2 == 0) {
  1132.             return 0;
  1133.             }
  1134.             if ((*pattern <= *string) && (c2 >= *string)) {
  1135.             break;
  1136.             }
  1137.             if ((*pattern >= *string) && (c2 <= *string)) {
  1138.             break;
  1139.             }
  1140.             pattern += 2;
  1141.         }
  1142.         pattern += 1;
  1143.         }
  1144.         while (*pattern != ']') {
  1145.         if (*pattern == 0) {
  1146.             pattern--;
  1147.             break;
  1148.         }
  1149.         pattern += 1;
  1150.         }
  1151.         goto thisCharOK;
  1152.     }
  1153.     
  1154.     /* If the next pattern character is '/', just strip off the '/'
  1155.      * so we do exact matching on the character that follows.
  1156.      */
  1157.     
  1158.     if (*pattern == '\\') {
  1159.         pattern += 1;
  1160.         if (*pattern == 0) {
  1161.         return 0;
  1162.         }
  1163.     }
  1164.  
  1165.     /* There's no special character.  Just make sure that the next
  1166.      * characters of each string match.
  1167.      */
  1168.     
  1169.     if (*pattern != *string) {
  1170.         return 0;
  1171.     }
  1172.  
  1173.     thisCharOK: pattern += 1;
  1174.     string += 1;
  1175.     }
  1176. }
  1177.  
  1178. /*
  1179.  *----------------------------------------------------------------------
  1180.  *
  1181.  * Tcl_SetResult --
  1182.  *
  1183.  *    Arrange for "string" to be the Tcl return value.
  1184.  *
  1185.  * Results:
  1186.  *    None.
  1187.  *
  1188.  * Side effects:
  1189.  *    interp->result is left pointing either to "string" (if "copy" is 0)
  1190.  *    or to a copy of string. Also, the object result is reset.
  1191.  *
  1192.  *----------------------------------------------------------------------
  1193.  */
  1194.  
  1195. void
  1196. Tcl_SetResult(interp, string, freeProc)
  1197.     Tcl_Interp *interp;        /* Interpreter with which to associate the
  1198.                  * return value. */
  1199.     char *string;        /* Value to be returned.  If NULL, the
  1200.                  * result is set to an empty string. */
  1201.     Tcl_FreeProc *freeProc;    /* Gives information about the string:
  1202.                  * TCL_STATIC, TCL_VOLATILE, or the address
  1203.                  * of a Tcl_FreeProc such as free. */
  1204. {
  1205.     Interp *iPtr = (Interp *) interp;
  1206.     int length;
  1207.     Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
  1208.     char *oldResult = iPtr->result;
  1209.  
  1210.     if (string == NULL) {
  1211.     iPtr->resultSpace[0] = 0;
  1212.     iPtr->result = iPtr->resultSpace;
  1213.     iPtr->freeProc = 0;
  1214.     } else if (freeProc == TCL_VOLATILE) {
  1215.     length = strlen(string);
  1216.     if (length > TCL_RESULT_SIZE) {
  1217.         iPtr->result = (char *) ckalloc((unsigned) length+1);
  1218.         iPtr->freeProc = TCL_DYNAMIC;
  1219.     } else {
  1220.         iPtr->result = iPtr->resultSpace;
  1221.         iPtr->freeProc = 0;
  1222.     }
  1223.     strcpy(iPtr->result, string);
  1224.     } else {
  1225.     iPtr->result = string;
  1226.     iPtr->freeProc = freeProc;
  1227.     }
  1228.  
  1229.     /*
  1230.      * If the old result was dynamically-allocated, free it up.  Do it
  1231.      * here, rather than at the beginning, in case the new result value
  1232.      * was part of the old result value.
  1233.      */
  1234.  
  1235.     if (oldFreeProc != 0) {
  1236.     if ((oldFreeProc == TCL_DYNAMIC)
  1237.         || (oldFreeProc == (Tcl_FreeProc *) free)) {
  1238.         ckfree(oldResult);
  1239.     } else {
  1240.         (*oldFreeProc)(oldResult);
  1241.     }
  1242.     }
  1243.  
  1244.     /*
  1245.      * Reset the object result since we just set the string result.
  1246.      */
  1247.  
  1248.     TclResetObjResult(iPtr);
  1249. }
  1250.  
  1251. /*
  1252.  *----------------------------------------------------------------------
  1253.  *
  1254.  * Tcl_GetStringResult --
  1255.  *
  1256.  *    Returns an interpreter's result value as a string.
  1257.  *
  1258.  * Results:
  1259.  *    The interpreter's result as a string.
  1260.  *
  1261.  * Side effects:
  1262.  *    If the string result is empty, the object result is moved to the
  1263.  *    string result, then the object result is reset.
  1264.  *
  1265.  *----------------------------------------------------------------------
  1266.  */
  1267.  
  1268. char *
  1269. Tcl_GetStringResult(interp)
  1270.      Tcl_Interp *interp;    /* Interpreter whose result to return. */
  1271. {
  1272.     /*
  1273.      * If the string result is empty, move the object result to the
  1274.      * string result, then reset the object result.
  1275.      * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
  1276.      */
  1277.     
  1278.     if (*(interp->result) == 0) {
  1279.     Tcl_SetResult(interp,
  1280.             TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL),
  1281.             TCL_VOLATILE);
  1282.     }
  1283.     return interp->result;
  1284. }
  1285.  
  1286. /*
  1287.  *----------------------------------------------------------------------
  1288.  *
  1289.  * Tcl_SetObjResult --
  1290.  *
  1291.  *    Arrange for objPtr to be an interpreter's result value.
  1292.  *
  1293.  * Results:
  1294.  *    None.
  1295.  *
  1296.  * Side effects:
  1297.  *    interp->objResultPtr is left pointing to the object referenced
  1298.  *    by objPtr. The object's reference count is incremented since
  1299.  *    there is now a new reference to it. The reference count for any
  1300.  *    old objResultPtr value is decremented. Also, the string result
  1301.  *    is reset.
  1302.  *
  1303.  *----------------------------------------------------------------------
  1304.  */
  1305.  
  1306. void
  1307. Tcl_SetObjResult(interp, objPtr)
  1308.     Tcl_Interp *interp;        /* Interpreter with which to associate the
  1309.                  * return object value. */
  1310.     Tcl_Obj *objPtr;        /* Tcl object to be returned. If NULL, the
  1311.                  * obj result is made an empty string
  1312.                  * object. */
  1313. {
  1314.     Interp *iPtr = (Interp *) interp;
  1315.     Tcl_Obj *oldObjResult = iPtr->objResultPtr;
  1316.  
  1317.     iPtr->objResultPtr = objPtr;
  1318.     Tcl_IncrRefCount(objPtr);    /* since interp result is a reference */
  1319.  
  1320.     /*
  1321.      * We wait until the end to release the old object result, in case
  1322.      * we are setting the result to itself.
  1323.      */
  1324.     
  1325.     TclDecrRefCount(oldObjResult);
  1326.  
  1327.     /*
  1328.      * Reset the string result since we just set the result object.
  1329.      */
  1330.  
  1331.     if (iPtr->freeProc != NULL) {
  1332.     if ((iPtr->freeProc == TCL_DYNAMIC)
  1333.             || (iPtr->freeProc == (Tcl_FreeProc *) free)) {
  1334.         ckfree(iPtr->result);
  1335.     } else {
  1336.         (*iPtr->freeProc)(iPtr->result);
  1337.     }
  1338.     iPtr->freeProc = 0;
  1339.     }
  1340.     iPtr->result = iPtr->resultSpace;
  1341.     iPtr->resultSpace[0] = 0;
  1342. }
  1343.  
  1344. /*
  1345.  *----------------------------------------------------------------------
  1346.  *
  1347.  * Tcl_GetObjResult --
  1348.  *
  1349.  *    Returns an interpreter's result value as a Tcl object. The object's
  1350.  *    reference count is not modified; the caller must do that if it
  1351.  *    needs to hold on to a long-term reference to it.
  1352.  *
  1353.  * Results:
  1354.  *    The interpreter's result as an object.
  1355.  *
  1356.  * Side effects:
  1357.  *    If the interpreter has a non-empty string result, the result object
  1358.  *    is either empty or stale because some procedure set interp->result
  1359.  *    directly. If so, the string result is moved to the result object
  1360.  *    then the string result is reset.
  1361.  *
  1362.  *----------------------------------------------------------------------
  1363.  */
  1364.  
  1365. Tcl_Obj *
  1366. Tcl_GetObjResult(interp)
  1367.     Tcl_Interp *interp;        /* Interpreter whose result to return. */
  1368. {
  1369.     Interp *iPtr = (Interp *) interp;
  1370.     Tcl_Obj *objResultPtr;
  1371.     int length;
  1372.  
  1373.     /*
  1374.      * If the string result is non-empty, move the string result to the
  1375.      * object result, then reset the string result.
  1376.      */
  1377.     
  1378.     if (*(iPtr->result) != 0) {
  1379.     TclResetObjResult(iPtr);
  1380.     
  1381.     objResultPtr = iPtr->objResultPtr;
  1382.     length = strlen(iPtr->result);
  1383.     TclInitStringRep(objResultPtr, iPtr->result, length);
  1384.     
  1385.     if (iPtr->freeProc != NULL) {
  1386.         if ((iPtr->freeProc == TCL_DYNAMIC)
  1387.                 || (iPtr->freeProc == (Tcl_FreeProc *) free)) {
  1388.         ckfree(iPtr->result);
  1389.         } else {
  1390.         (*iPtr->freeProc)(iPtr->result);
  1391.         }
  1392.         iPtr->freeProc = 0;
  1393.     }
  1394.     iPtr->result = iPtr->resultSpace;
  1395.     iPtr->resultSpace[0] = 0;
  1396.     }
  1397.     return iPtr->objResultPtr;
  1398. }
  1399.  
  1400. /*
  1401.  *----------------------------------------------------------------------
  1402.  *
  1403.  * Tcl_AppendResult --
  1404.  *
  1405.  *    Append a variable number of strings onto the interpreter's string
  1406.  *    result.
  1407.  *
  1408.  * Results:
  1409.  *    None.
  1410.  *
  1411.  * Side effects:
  1412.  *    The result of the interpreter given by the first argument is
  1413.  *    extended by the strings given by the second and following arguments
  1414.  *    (up to a terminating NULL argument).
  1415.  *
  1416.  *    If the string result is empty, the object result is moved to the
  1417.  *    string result, then the object result is reset.
  1418.  *
  1419.  *----------------------------------------------------------------------
  1420.  */
  1421.  
  1422. void
  1423. Tcl_AppendResult TCL_VARARGS_DEF(Tcl_Interp *,arg1)
  1424. {
  1425.     va_list argList;
  1426.     Interp *iPtr;
  1427.     char *string;
  1428.     int newSpace;
  1429.  
  1430.     /*
  1431.      * If the string result is empty, move the object result to the
  1432.      * string result, then reset the object result.
  1433.      * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
  1434.      */
  1435.  
  1436.     iPtr = (Interp *) TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
  1437.     if (*(iPtr->result) == 0) {
  1438.     Tcl_SetResult((Tcl_Interp *) iPtr,
  1439.             TclGetStringFromObj(Tcl_GetObjResult((Tcl_Interp *) iPtr),
  1440.                 (int *) NULL),
  1441.             TCL_VOLATILE);
  1442.     }
  1443.     
  1444.     /*
  1445.      * Scan through all the arguments to see how much space is needed.
  1446.      */
  1447.  
  1448.     newSpace = 0;
  1449.     while (1) {
  1450.     string = va_arg(argList, char *);
  1451.     if (string == NULL) {
  1452.         break;
  1453.     }
  1454.     newSpace += strlen(string);
  1455.     }
  1456.     va_end(argList);
  1457.  
  1458.     /*
  1459.      * If the append buffer isn't already setup and large enough to hold
  1460.      * the new data, set it up.
  1461.      */
  1462.  
  1463.     if ((iPtr->result != iPtr->appendResult)
  1464.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1465.         || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1466.        SetupAppendBuffer(iPtr, newSpace);
  1467.     }
  1468.  
  1469.     /*
  1470.      * Now go through all the argument strings again, copying them into the
  1471.      * buffer.
  1472.      */
  1473.  
  1474.     TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
  1475.     while (1) {
  1476.     string = va_arg(argList, char *);
  1477.     if (string == NULL) {
  1478.         break;
  1479.     }
  1480.     strcpy(iPtr->appendResult + iPtr->appendUsed, string);
  1481.     iPtr->appendUsed += strlen(string);
  1482.     }
  1483.     va_end(argList);
  1484. }
  1485.  
  1486. /*
  1487.  *----------------------------------------------------------------------
  1488.  *
  1489.  * Tcl_AppendElement --
  1490.  *
  1491.  *    Convert a string to a valid Tcl list element and append it to the
  1492.  *    result (which is ostensibly a list).
  1493.  *
  1494.  * Results:
  1495.  *    None.
  1496.  *
  1497.  * Side effects:
  1498.  *    The result in the interpreter given by the first argument is
  1499.  *    extended with a list element converted from string. A separator
  1500.  *    space is added before the converted list element unless the current
  1501.  *    result is empty, contains the single character "{", or ends in " {".
  1502.  *
  1503.  *    If the string result is empty, the object result is moved to the
  1504.  *    string result, then the object result is reset.
  1505.  *
  1506.  *----------------------------------------------------------------------
  1507.  */
  1508.  
  1509. void
  1510. Tcl_AppendElement(interp, string)
  1511.     Tcl_Interp *interp;        /* Interpreter whose result is to be
  1512.                  * extended. */
  1513.     char *string;        /* String to convert to list element and
  1514.                  * add to result. */
  1515. {
  1516.     Interp *iPtr = (Interp *) interp;
  1517.     char *dst;
  1518.     int size;
  1519.     int flags;
  1520.  
  1521.     /*
  1522.      * If the string result is empty, move the object result to the
  1523.      * string result, then reset the object result.
  1524.      * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
  1525.      */
  1526.  
  1527.     if (*(iPtr->result) == 0) {
  1528.     Tcl_SetResult(interp,
  1529.             TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL),
  1530.             TCL_VOLATILE);
  1531.     }
  1532.  
  1533.     /*
  1534.      * See how much space is needed, and grow the append buffer if
  1535.      * needed to accommodate the list element.
  1536.      */
  1537.  
  1538.     size = Tcl_ScanElement(string, &flags) + 1;
  1539.     if ((iPtr->result != iPtr->appendResult)
  1540.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1541.         || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1542.        SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
  1543.     }
  1544.  
  1545.     /*
  1546.      * Convert the string into a list element and copy it to the
  1547.      * buffer that's forming, with a space separator if needed.
  1548.      */
  1549.  
  1550.     dst = iPtr->appendResult + iPtr->appendUsed;
  1551.     if (TclNeedSpace(iPtr->appendResult, dst)) {
  1552.     iPtr->appendUsed++;
  1553.     *dst = ' ';
  1554.     dst++;
  1555.     }
  1556.     iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
  1557. }
  1558.  
  1559. /*
  1560.  *----------------------------------------------------------------------
  1561.  *
  1562.  * SetupAppendBuffer --
  1563.  *
  1564.  *    This procedure makes sure that there is an append buffer properly
  1565.  *    initialized, if necessary, from the interpreter's result, and
  1566.  *    that it has at least enough room to accommodate newSpace new
  1567.  *    bytes of information.
  1568.  *
  1569.  * Results:
  1570.  *    None.
  1571.  *
  1572.  * Side effects:
  1573.  *    None.
  1574.  *
  1575.  *----------------------------------------------------------------------
  1576.  */
  1577.  
  1578. static void
  1579. SetupAppendBuffer(iPtr, newSpace)
  1580.     Interp *iPtr;        /* Interpreter whose result is being set up. */
  1581.     int newSpace;        /* Make sure that at least this many bytes
  1582.                  * of new information may be added. */
  1583. {
  1584.     int totalSpace;
  1585.  
  1586.     /*
  1587.      * Make the append buffer larger, if that's necessary, then copy the
  1588.      * result into the append buffer and make the append buffer the official
  1589.      * Tcl result.
  1590.      */
  1591.  
  1592.     if (iPtr->result != iPtr->appendResult) {
  1593.     /*
  1594.      * If an oversized buffer was used recently, then free it up
  1595.      * so we go back to a smaller buffer.  This avoids tying up
  1596.      * memory forever after a large operation.
  1597.      */
  1598.  
  1599.     if (iPtr->appendAvl > 500) {
  1600.         ckfree(iPtr->appendResult);
  1601.         iPtr->appendResult = NULL;
  1602.         iPtr->appendAvl = 0;
  1603.     }
  1604.     iPtr->appendUsed = strlen(iPtr->result);
  1605.     } else if (iPtr->result[iPtr->appendUsed] != 0) {
  1606.     /*
  1607.      * Most likely someone has modified a result created by
  1608.      * Tcl_AppendResult et al. so that it has a different size.
  1609.      * Just recompute the size.
  1610.      */
  1611.  
  1612.     iPtr->appendUsed = strlen(iPtr->result);
  1613.     }
  1614.     
  1615.     totalSpace = newSpace + iPtr->appendUsed;
  1616.     if (totalSpace >= iPtr->appendAvl) {
  1617.     char *new;
  1618.  
  1619.     if (totalSpace < 100) {
  1620.         totalSpace = 200;
  1621.     } else {
  1622.         totalSpace *= 2;
  1623.     }
  1624.     new = (char *) ckalloc((unsigned) totalSpace);
  1625.     strcpy(new, iPtr->result);
  1626.     if (iPtr->appendResult != NULL) {
  1627.         ckfree(iPtr->appendResult);
  1628.     }
  1629.     iPtr->appendResult = new;
  1630.     iPtr->appendAvl = totalSpace;
  1631.     } else if (iPtr->result != iPtr->appendResult) {
  1632.     strcpy(iPtr->appendResult, iPtr->result);
  1633.     }
  1634.     
  1635.     Tcl_FreeResult((Tcl_Interp *) iPtr);
  1636.     iPtr->result = iPtr->appendResult;
  1637. }
  1638.  
  1639. /*
  1640.  *----------------------------------------------------------------------
  1641.  *
  1642.  * Tcl_FreeResult --
  1643.  *
  1644.  *    This procedure frees up the memory associated with an interpreter's
  1645.  *    string result. It also resets the interpreter's result object.
  1646.  *    Tcl_FreeResult is most commonly used when a procedure is about to
  1647.  *    replace one result value with another.
  1648.  *
  1649.  * Results:
  1650.  *    None.
  1651.  *
  1652.  * Side effects:
  1653.  *    Frees the memory associated with interp's string result and sets
  1654.  *    interp->freeProc to zero, but does not change interp->result or
  1655.  *    clear error state. Resets interp's result object to an unshared
  1656.  *    empty object.
  1657.  *
  1658.  *----------------------------------------------------------------------
  1659.  */
  1660.  
  1661. void
  1662. Tcl_FreeResult(interp)
  1663.     Tcl_Interp *interp;        /* Interpreter for which to free result. */
  1664. {
  1665.     Interp *iPtr = (Interp *) interp;
  1666.     
  1667.     if (iPtr->freeProc != NULL) {
  1668.     if ((iPtr->freeProc == TCL_DYNAMIC)
  1669.             || (iPtr->freeProc == (Tcl_FreeProc *) free)) {
  1670.         ckfree(iPtr->result);
  1671.     } else {
  1672.         (*iPtr->freeProc)(iPtr->result);
  1673.     }
  1674.     iPtr->freeProc = 0;
  1675.     }
  1676.     
  1677.     TclResetObjResult(iPtr);
  1678. }
  1679.  
  1680. /*
  1681.  *----------------------------------------------------------------------
  1682.  *
  1683.  * Tcl_ResetResult --
  1684.  *
  1685.  *    This procedure resets both the interpreter's string and object
  1686.  *    results.
  1687.  *
  1688.  * Results:
  1689.  *    None.
  1690.  *
  1691.  * Side effects:
  1692.  *    It resets the result object to an unshared empty object. It
  1693.  *    then restores the interpreter's string result area to its default
  1694.  *    initialized state, freeing up any memory that may have been
  1695.  *    allocated. It also clears any error information for the interpreter.
  1696.  *
  1697.  *----------------------------------------------------------------------
  1698.  */
  1699.  
  1700. void
  1701. Tcl_ResetResult(interp)
  1702.     Tcl_Interp *interp;        /* Interpreter for which to clear result. */
  1703. {
  1704.     Interp *iPtr = (Interp *) interp;
  1705.  
  1706.     TclResetObjResult(iPtr);
  1707.     
  1708.     Tcl_FreeResult(interp);
  1709.     iPtr->result = iPtr->resultSpace;
  1710.     iPtr->resultSpace[0] = 0;
  1711.     
  1712.     iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
  1713. }
  1714.  
  1715. /*
  1716.  *----------------------------------------------------------------------
  1717.  *
  1718.  * Tcl_SetErrorCode --
  1719.  *
  1720.  *    This procedure is called to record machine-readable information
  1721.  *    about an error that is about to be returned.
  1722.  *
  1723.  * Results:
  1724.  *    None.
  1725.  *
  1726.  * Side effects:
  1727.  *    The errorCode global variable is modified to hold all of the
  1728.  *    arguments to this procedure, in a list form with each argument
  1729.  *    becoming one element of the list.  A flag is set internally
  1730.  *    to remember that errorCode has been set, so the variable doesn't
  1731.  *    get set automatically when the error is returned.
  1732.  *
  1733.  *----------------------------------------------------------------------
  1734.  */
  1735.     /* VARARGS2 */
  1736. void
  1737. Tcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1)
  1738. {
  1739.     va_list argList;
  1740.     char *string;
  1741.     int flags;
  1742.     Interp *iPtr;
  1743.  
  1744.     /*
  1745.      * Scan through the arguments one at a time, appending them to
  1746.      * $errorCode as list elements.
  1747.      */
  1748.  
  1749.     iPtr = (Interp *) TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
  1750.     flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
  1751.     while (1) {
  1752.     string = va_arg(argList, char *);
  1753.     if (string == NULL) {
  1754.         break;
  1755.     }
  1756.     (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
  1757.         (char *) NULL, string, flags);
  1758.     flags |= TCL_APPEND_VALUE;
  1759.     }
  1760.     va_end(argList);
  1761.     iPtr->flags |= ERROR_CODE_SET;
  1762. }
  1763.  
  1764. /*
  1765.  *----------------------------------------------------------------------
  1766.  *
  1767.  * Tcl_SetObjErrorCode --
  1768.  *
  1769.  *    This procedure is called to record machine-readable information
  1770.  *    about an error that is about to be returned. The caller should
  1771.  *    build a list object up and pass it to this routine.
  1772.  *
  1773.  * Results:
  1774.  *    None.
  1775.  *
  1776.  * Side effects:
  1777.  *    The errorCode global variable is modified to be the new value.
  1778.  *    A flag is set internally to remember that errorCode has been
  1779.  *    set, so the variable doesn't get set automatically when the
  1780.  *    error is returned.
  1781.  *
  1782.  *----------------------------------------------------------------------
  1783.  */
  1784.  
  1785. void
  1786. Tcl_SetObjErrorCode(interp, errorObjPtr)
  1787.     Tcl_Interp *interp;
  1788.     Tcl_Obj *errorObjPtr;
  1789. {
  1790.     Tcl_Obj *namePtr;
  1791.     Interp *iPtr;
  1792.     
  1793.     namePtr = Tcl_NewStringObj("errorCode", -1);
  1794.     iPtr = (Interp *) interp;
  1795.     Tcl_ObjSetVar2(interp, namePtr, (Tcl_Obj *) NULL, errorObjPtr,
  1796.         TCL_GLOBAL_ONLY);
  1797.     iPtr->flags |= ERROR_CODE_SET;
  1798.     Tcl_DecrRefCount(namePtr);
  1799. }
  1800.  
  1801. /*
  1802.  *----------------------------------------------------------------------
  1803.  *
  1804.  * Tcl_RegExpCompile --
  1805.  *
  1806.  *    Compile a regular expression into a form suitable for fast
  1807.  *    matching.  This procedure retains a small cache of pre-compiled
  1808.  *    regular expressions in the interpreter, in order to avoid
  1809.  *    compilation costs as much as possible.
  1810.  *
  1811.  * Results:
  1812.  *    The return value is a pointer to the compiled form of string,
  1813.  *    suitable for passing to Tcl_RegExpExec.  This compiled form
  1814.  *    is only valid up until the next call to this procedure, so
  1815.  *    don't keep these around for a long time!  If an error occurred
  1816.  *    while compiling the pattern, then NULL is returned and an error
  1817.  *    message is left in interp->result.
  1818.  *
  1819.  * Side effects:
  1820.  *    The cache of compiled regexp's in interp will be modified to
  1821.  *    hold information for string, if such information isn't already
  1822.  *    present in the cache.
  1823.  *
  1824.  *----------------------------------------------------------------------
  1825.  */
  1826.  
  1827. Tcl_RegExp
  1828. Tcl_RegExpCompile(interp, string)
  1829.     Tcl_Interp *interp;            /* For use in error reporting. */
  1830.     char *string;            /* String for which to produce
  1831.                      * compiled regular expression. */
  1832. {
  1833.     Interp *iPtr = (Interp *) interp;
  1834.     int i, length;
  1835.     regexp *result;
  1836.  
  1837.     length = strlen(string);
  1838.     for (i = 0; i < NUM_REGEXPS; i++) {
  1839.     if ((length == iPtr->patLengths[i])
  1840.         && (strcmp(string, iPtr->patterns[i]) == 0)) {
  1841.         /*
  1842.          * Move the matched pattern to the first slot in the
  1843.          * cache and shift the other patterns down one position.
  1844.          */
  1845.  
  1846.         if (i != 0) {
  1847.         int j;
  1848.         char *cachedString;
  1849.  
  1850.         cachedString = iPtr->patterns[i];
  1851.         result = iPtr->regexps[i];
  1852.         for (j = i-1; j >= 0; j--) {
  1853.             iPtr->patterns[j+1] = iPtr->patterns[j];
  1854.             iPtr->patLengths[j+1] = iPtr->patLengths[j];
  1855.             iPtr->regexps[j+1] = iPtr->regexps[j];
  1856.         }
  1857.         iPtr->patterns[0] = cachedString;
  1858.         iPtr->patLengths[0] = length;
  1859.         iPtr->regexps[0] = result;
  1860.         }
  1861.         return (Tcl_RegExp) iPtr->regexps[0];
  1862.     }
  1863.     }
  1864.  
  1865.     /*
  1866.      * No match in the cache.  Compile the string and add it to the
  1867.      * cache.
  1868.      */
  1869.  
  1870.     TclRegError((char *) NULL);
  1871.     result = TclRegComp(string);
  1872.     if (TclGetRegError() != NULL) {
  1873.     Tcl_AppendResult(interp,
  1874.         "couldn't compile regular expression pattern: ",
  1875.         TclGetRegError(), (char *) NULL);
  1876.     return NULL;
  1877.     }
  1878.     if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
  1879.     ckfree(iPtr->patterns[NUM_REGEXPS-1]);
  1880.     ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
  1881.     }
  1882.     for (i = NUM_REGEXPS - 2; i >= 0; i--) {
  1883.     iPtr->patterns[i+1] = iPtr->patterns[i];
  1884.     iPtr->patLengths[i+1] = iPtr->patLengths[i];
  1885.     iPtr->regexps[i+1] = iPtr->regexps[i];
  1886.     }
  1887.     iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
  1888.     strcpy(iPtr->patterns[0], string);
  1889.     iPtr->patLengths[0] = length;
  1890.     iPtr->regexps[0] = result;
  1891.     return (Tcl_RegExp) result;
  1892. }
  1893.  
  1894. /*
  1895.  *----------------------------------------------------------------------
  1896.  *
  1897.  * Tcl_RegExpExec --
  1898.  *
  1899.  *    Execute the regular expression matcher using a compiled form
  1900.  *    of a regular expression and save information about any match
  1901.  *    that is found.
  1902.  *
  1903.  * Results:
  1904.  *    If an error occurs during the matching operation then -1
  1905.  *    is returned and interp->result contains an error message.
  1906.  *    Otherwise the return value is 1 if a matching range is
  1907.  *    found and 0 if there is no matching range.
  1908.  *
  1909.  * Side effects:
  1910.  *    None.
  1911.  *
  1912.  *----------------------------------------------------------------------
  1913.  */
  1914.  
  1915. int
  1916. Tcl_RegExpExec(interp, re, string, start)
  1917.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  1918.     Tcl_RegExp re;        /* Compiled regular expression;  must have
  1919.                  * been returned by previous call to
  1920.                  * Tcl_RegExpCompile. */
  1921.     char *string;        /* String against which to match re. */
  1922.     char *start;        /* If string is part of a larger string,
  1923.                  * this identifies beginning of larger
  1924.                  * string, so that "^" won't match. */
  1925. {
  1926.     int match;
  1927.  
  1928.     regexp *regexpPtr = (regexp *) re;
  1929.     TclRegError((char *) NULL);
  1930.     match = TclRegExec(regexpPtr, string, start);
  1931.     if (TclGetRegError() != NULL) {
  1932.     Tcl_ResetResult(interp);
  1933.     Tcl_AppendResult(interp, "error while matching regular expression: ",
  1934.         TclGetRegError(), (char *) NULL);
  1935.     return -1;
  1936.     }
  1937.     return match;
  1938. }
  1939.  
  1940. /*
  1941.  *----------------------------------------------------------------------
  1942.  *
  1943.  * Tcl_RegExpRange --
  1944.  *
  1945.  *    Returns pointers describing the range of a regular expression match,
  1946.  *    or one of the subranges within the match.
  1947.  *
  1948.  * Results:
  1949.  *    The variables at *startPtr and *endPtr are modified to hold the
  1950.  *    addresses of the endpoints of the range given by index.  If the
  1951.  *    specified range doesn't exist then NULLs are returned.
  1952.  *
  1953.  * Side effects:
  1954.  *    None.
  1955.  *
  1956.  *----------------------------------------------------------------------
  1957.  */
  1958.  
  1959. void
  1960. Tcl_RegExpRange(re, index, startPtr, endPtr)
  1961.     Tcl_RegExp re;        /* Compiled regular expression that has
  1962.                  * been passed to Tcl_RegExpExec. */
  1963.     int index;            /* 0 means give the range of the entire
  1964.                  * match, > 0 means give the range of
  1965.                  * a matching subrange.  Must be no greater
  1966.                  * than NSUBEXP. */
  1967.     char **startPtr;        /* Store address of first character in
  1968.                  * (sub-) range here. */
  1969.     char **endPtr;        /* Store address of character just after last
  1970.                  * in (sub-) range here. */
  1971. {
  1972.     regexp *regexpPtr = (regexp *) re;
  1973.  
  1974.     if (index >= NSUBEXP) {
  1975.     *startPtr = *endPtr = NULL;
  1976.     } else {
  1977.     *startPtr = regexpPtr->startp[index];
  1978.     *endPtr = regexpPtr->endp[index];
  1979.     }
  1980. }
  1981.  
  1982. /*
  1983.  *----------------------------------------------------------------------
  1984.  *
  1985.  * Tcl_RegExpMatch --
  1986.  *
  1987.  *    See if a string matches a regular expression.
  1988.  *
  1989.  * Results:
  1990.  *    If an error occurs during the matching operation then -1
  1991.  *    is returned and interp->result contains an error message.
  1992.  *    Otherwise the return value is 1 if "string" matches "pattern"
  1993.  *    and 0 otherwise.
  1994.  *
  1995.  * Side effects:
  1996.  *    None.
  1997.  *
  1998.  *----------------------------------------------------------------------
  1999.  */
  2000.  
  2001. int
  2002. Tcl_RegExpMatch(interp, string, pattern)
  2003.     Tcl_Interp *interp;        /* Used for error reporting. */
  2004.     char *string;        /* String. */
  2005.     char *pattern;        /* Regular expression to match against
  2006.                  * string. */
  2007. {
  2008.     Tcl_RegExp re;
  2009.  
  2010.     re = Tcl_RegExpCompile(interp, pattern);
  2011.     if (re == NULL) {
  2012.     return -1;
  2013.     }
  2014.     return Tcl_RegExpExec(interp, re, string, string);
  2015. }
  2016.  
  2017. /*
  2018.  *----------------------------------------------------------------------
  2019.  *
  2020.  * Tcl_DStringInit --
  2021.  *
  2022.  *    Initializes a dynamic string, discarding any previous contents
  2023.  *    of the string (Tcl_DStringFree should have been called already
  2024.  *    if the dynamic string was previously in use).
  2025.  *
  2026.  * Results:
  2027.  *    None.
  2028.  *
  2029.  * Side effects:
  2030.  *    The dynamic string is initialized to be empty.
  2031.  *
  2032.  *----------------------------------------------------------------------
  2033.  */
  2034.  
  2035. void
  2036. Tcl_DStringInit(dsPtr)
  2037.     Tcl_DString *dsPtr;        /* Pointer to structure for dynamic string. */
  2038. {
  2039.     dsPtr->string = dsPtr->staticSpace;
  2040.     dsPtr->length = 0;
  2041.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  2042.     dsPtr->staticSpace[0] = 0;
  2043. }
  2044.  
  2045. /*
  2046.  *----------------------------------------------------------------------
  2047.  *
  2048.  * Tcl_DStringAppend --
  2049.  *
  2050.  *    Append more characters to the current value of a dynamic string.
  2051.  *
  2052.  * Results:
  2053.  *    The return value is a pointer to the dynamic string's new value.
  2054.  *
  2055.  * Side effects:
  2056.  *    Length bytes from string (or all of string if length is less
  2057.  *    than zero) are added to the current value of the string. Memory
  2058.  *    gets reallocated if needed to accomodate the string's new size.
  2059.  *
  2060.  *----------------------------------------------------------------------
  2061.  */
  2062.  
  2063. char *
  2064. Tcl_DStringAppend(dsPtr, string, length)
  2065.     Tcl_DString *dsPtr;        /* Structure describing dynamic string. */
  2066.     CONST char *string;        /* String to append.  If length is -1 then
  2067.                  * this must be null-terminated. */
  2068.     int length;            /* Number of characters from string to
  2069.                  * append.  If < 0, then append all of string,
  2070.                  * up to null at end. */
  2071. {
  2072.     int newSize;
  2073.     char *newString, *dst;
  2074.     CONST char *end;
  2075.  
  2076.     if (length < 0) {
  2077.     length = strlen(string);
  2078.     }
  2079.     newSize = length + dsPtr->length;
  2080.  
  2081.     /*
  2082.      * Allocate a larger buffer for the string if the current one isn't
  2083.      * large enough. Allocate extra space in the new buffer so that there
  2084.      * will be room to grow before we have to allocate again.
  2085.      */
  2086.  
  2087.     if (newSize >= dsPtr->spaceAvl) {
  2088.     dsPtr->spaceAvl = newSize*2;
  2089.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  2090.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  2091.         (size_t) dsPtr->length);
  2092.     if (dsPtr->string != dsPtr->staticSpace) {
  2093.         ckfree(dsPtr->string);
  2094.     }
  2095.     dsPtr->string = newString;
  2096.     }
  2097.  
  2098.     /*
  2099.      * Copy the new string into the buffer at the end of the old
  2100.      * one.
  2101.      */
  2102.  
  2103.     for (dst = dsPtr->string + dsPtr->length, end = string+length;
  2104.         string < end; string++, dst++) {
  2105.     *dst = *string;
  2106.     }
  2107.     *dst = '\0';
  2108.     dsPtr->length += length;
  2109.     return dsPtr->string;
  2110. }
  2111.  
  2112. /*
  2113.  *----------------------------------------------------------------------
  2114.  *
  2115.  * Tcl_DStringAppendElement --
  2116.  *
  2117.  *    Append a list element to the current value of a dynamic string.
  2118.  *
  2119.  * Results:
  2120.  *    The return value is a pointer to the dynamic string's new value.
  2121.  *
  2122.  * Side effects:
  2123.  *    String is reformatted as a list element and added to the current
  2124.  *    value of the string.  Memory gets reallocated if needed to
  2125.  *    accomodate the string's new size.
  2126.  *
  2127.  *----------------------------------------------------------------------
  2128.  */
  2129.  
  2130. char *
  2131. Tcl_DStringAppendElement(dsPtr, string)
  2132.     Tcl_DString *dsPtr;        /* Structure describing dynamic string. */
  2133.     CONST char *string;        /* String to append.  Must be
  2134.                  * null-terminated. */
  2135. {
  2136.     int newSize, flags;
  2137.     char *dst, *newString;
  2138.  
  2139.     newSize = Tcl_ScanElement(string, &flags) + dsPtr->length + 1;
  2140.  
  2141.     /*
  2142.      * Allocate a larger buffer for the string if the current one isn't
  2143.      * large enough.  Allocate extra space in the new buffer so that there
  2144.      * will be room to grow before we have to allocate again.
  2145.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  2146.      * to a larger buffer, since there may be embedded NULLs in the
  2147.      * string in some cases.
  2148.      */
  2149.  
  2150.     if (newSize >= dsPtr->spaceAvl) {
  2151.     dsPtr->spaceAvl = newSize*2;
  2152.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  2153.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  2154.         (size_t) dsPtr->length);
  2155.     if (dsPtr->string != dsPtr->staticSpace) {
  2156.         ckfree(dsPtr->string);
  2157.     }
  2158.     dsPtr->string = newString;
  2159.     }
  2160.  
  2161.     /*
  2162.      * Convert the new string to a list element and copy it into the
  2163.      * buffer at the end, with a space, if needed.
  2164.      */
  2165.  
  2166.     dst = dsPtr->string + dsPtr->length;
  2167.     if (TclNeedSpace(dsPtr->string, dst)) {
  2168.     *dst = ' ';
  2169.     dst++;
  2170.     dsPtr->length++;
  2171.     }
  2172.     dsPtr->length += Tcl_ConvertElement(string, dst, flags);
  2173.     return dsPtr->string;
  2174. }
  2175.  
  2176. /*
  2177.  *----------------------------------------------------------------------
  2178.  *
  2179.  * Tcl_DStringSetLength --
  2180.  *
  2181.  *    Change the length of a dynamic string.  This can cause the
  2182.  *    string to either grow or shrink, depending on the value of
  2183.  *    length.
  2184.  *
  2185.  * Results:
  2186.  *    None.
  2187.  *
  2188.  * Side effects:
  2189.  *    The length of dsPtr is changed to length and a null byte is
  2190.  *    stored at that position in the string.  If length is larger
  2191.  *    than the space allocated for dsPtr, then a panic occurs.
  2192.  *
  2193.  *----------------------------------------------------------------------
  2194.  */
  2195.  
  2196. void
  2197. Tcl_DStringSetLength(dsPtr, length)
  2198.     Tcl_DString *dsPtr;        /* Structure describing dynamic string. */
  2199.     int length;            /* New length for dynamic string. */
  2200. {
  2201.     if (length < 0) {
  2202.     length = 0;
  2203.     }
  2204.     if (length >= dsPtr->spaceAvl) {
  2205.     char *newString;
  2206.  
  2207.     dsPtr->spaceAvl = length+1;
  2208.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  2209.  
  2210.     /*
  2211.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  2212.      * to a larger buffer, since there may be embedded NULLs in the
  2213.      * string in some cases.
  2214.      */
  2215.  
  2216.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  2217.         (size_t) dsPtr->length);
  2218.     if (dsPtr->string != dsPtr->staticSpace) {
  2219.         ckfree(dsPtr->string);
  2220.     }
  2221.     dsPtr->string = newString;
  2222.     }
  2223.     dsPtr->length = length;
  2224.     dsPtr->string[length] = 0;
  2225. }
  2226.  
  2227. /*
  2228.  *----------------------------------------------------------------------
  2229.  *
  2230.  * Tcl_DStringFree --
  2231.  *
  2232.  *    Frees up any memory allocated for the dynamic string and
  2233.  *    reinitializes the string to an empty state.
  2234.  *
  2235.  * Results:
  2236.  *    None.
  2237.  *
  2238.  * Side effects:
  2239.  *    The previous contents of the dynamic string are lost, and
  2240.  *    the new value is an empty string.
  2241.  *
  2242.  *----------------------------------------------------------------------
  2243.  */
  2244.  
  2245. void
  2246. Tcl_DStringFree(dsPtr)
  2247.     Tcl_DString *dsPtr;        /* Structure describing dynamic string. */
  2248. {
  2249.     if (dsPtr->string != dsPtr->staticSpace) {
  2250.     ckfree(dsPtr->string);
  2251.     }
  2252.     dsPtr->string = dsPtr->staticSpace;
  2253.     dsPtr->length = 0;
  2254.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  2255.     dsPtr->staticSpace[0] = 0;
  2256. }
  2257.  
  2258. /*
  2259.  *----------------------------------------------------------------------
  2260.  *
  2261.  * Tcl_DStringResult --
  2262.  *
  2263.  *    This procedure moves the value of a dynamic string into an
  2264.  *    interpreter as its string result. Afterwards, the dynamic string
  2265.  *    is reset to an empty string.
  2266.  *
  2267.  * Results:
  2268.  *    None.
  2269.  *
  2270.  * Side effects:
  2271.  *    The string is "moved" to interp's result, and any existing
  2272.  *    string result for interp is freed. dsPtr is reinitialized to
  2273.  *    an empty string.
  2274.  *
  2275.  *----------------------------------------------------------------------
  2276.  */
  2277.  
  2278. void
  2279. Tcl_DStringResult(interp, dsPtr)
  2280.     Tcl_Interp *interp;        /* Interpreter whose result is to be reset. */
  2281.     Tcl_DString *dsPtr;        /* Dynamic string that is to become the
  2282.                  * result of interp. */
  2283. {
  2284.     Tcl_ResetResult(interp);
  2285.     
  2286.     if (dsPtr->string != dsPtr->staticSpace) {
  2287.     interp->result = dsPtr->string;
  2288.     interp->freeProc = TCL_DYNAMIC;
  2289.     } else if (dsPtr->length < TCL_RESULT_SIZE) {
  2290.     interp->result = ((Interp *) interp)->resultSpace;
  2291.     strcpy(interp->result, dsPtr->string);
  2292.     } else {
  2293.     Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
  2294.     }
  2295.     
  2296.     dsPtr->string = dsPtr->staticSpace;
  2297.     dsPtr->length = 0;
  2298.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  2299.     dsPtr->staticSpace[0] = 0;
  2300. }
  2301.  
  2302. /*
  2303.  *----------------------------------------------------------------------
  2304.  *
  2305.  * Tcl_DStringGetResult --
  2306.  *
  2307.  *    This procedure moves an interpreter's result into a dynamic string.
  2308.  *
  2309.  * Results:
  2310.  *    None.
  2311.  *
  2312.  * Side effects:
  2313.  *    The interpreter's string result is cleared, and the previous
  2314.  *    contents of dsPtr are freed.
  2315.  *
  2316.  *    If the string result is empty, the object result is moved to the
  2317.  *    string result, then the object result is reset.
  2318.  *
  2319.  *----------------------------------------------------------------------
  2320.  */
  2321.  
  2322. void
  2323. Tcl_DStringGetResult(interp, dsPtr)
  2324.     Tcl_Interp *interp;        /* Interpreter whose result is to be reset. */
  2325.     Tcl_DString *dsPtr;        /* Dynamic string that is to become the
  2326.                  * result of interp. */
  2327. {
  2328.     Interp *iPtr = (Interp *) interp;
  2329.     
  2330.     if (dsPtr->string != dsPtr->staticSpace) {
  2331.     ckfree(dsPtr->string);
  2332.     }
  2333.  
  2334.     /*
  2335.      * If the string result is empty, move the object result to the
  2336.      * string result, then reset the object result.
  2337.      * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
  2338.      */
  2339.  
  2340.     if (*(iPtr->result) == 0) {
  2341.     Tcl_SetResult(interp,
  2342.             TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL),
  2343.             TCL_VOLATILE);
  2344.     }
  2345.  
  2346.     dsPtr->length = strlen(iPtr->result);
  2347.     if (iPtr->freeProc != NULL) {
  2348.     if ((iPtr->freeProc == TCL_DYNAMIC)
  2349.         || (iPtr->freeProc == (Tcl_FreeProc *) free)) {
  2350.         dsPtr->string = iPtr->result;
  2351.         dsPtr->spaceAvl = dsPtr->length+1;
  2352.     } else {
  2353.         dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1));
  2354.         strcpy(dsPtr->string, iPtr->result);
  2355.         (*iPtr->freeProc)(iPtr->result);
  2356.     }
  2357.     dsPtr->spaceAvl = dsPtr->length+1;
  2358.     iPtr->freeProc = NULL;
  2359.     } else {
  2360.     if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
  2361.         dsPtr->string = dsPtr->staticSpace;
  2362.         dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  2363.     } else {
  2364.         dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1));
  2365.         dsPtr->spaceAvl = dsPtr->length + 1;
  2366.     }
  2367.     strcpy(dsPtr->string, iPtr->result);
  2368.     }
  2369.     
  2370.     iPtr->result = iPtr->resultSpace;
  2371.     iPtr->resultSpace[0] = 0;
  2372. }
  2373.  
  2374. /*
  2375.  *----------------------------------------------------------------------
  2376.  *
  2377.  * Tcl_DStringStartSublist --
  2378.  *
  2379.  *    This procedure adds the necessary information to a dynamic
  2380.  *    string (e.g. " {" to start a sublist.  Future element
  2381.  *    appends will be in the sublist rather than the main list.
  2382.  *
  2383.  * Results:
  2384.  *    None.
  2385.  *
  2386.  * Side effects:
  2387.  *    Characters get added to the dynamic string.
  2388.  *
  2389.  *----------------------------------------------------------------------
  2390.  */
  2391.  
  2392. void
  2393. Tcl_DStringStartSublist(dsPtr)
  2394.     Tcl_DString *dsPtr;            /* Dynamic string. */
  2395. {
  2396.     if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
  2397.     Tcl_DStringAppend(dsPtr, " {", -1);
  2398.     } else {
  2399.     Tcl_DStringAppend(dsPtr, "{", -1);
  2400.     }
  2401. }
  2402.  
  2403. /*
  2404.  *----------------------------------------------------------------------
  2405.  *
  2406.  * Tcl_DStringEndSublist --
  2407.  *
  2408.  *    This procedure adds the necessary characters to a dynamic
  2409.  *    string to end a sublist (e.g. "}").  Future element appends
  2410.  *    will be in the enclosing (sub)list rather than the current
  2411.  *    sublist.
  2412.  *
  2413.  * Results:
  2414.  *    None.
  2415.  *
  2416.  * Side effects:
  2417.  *    None.
  2418.  *
  2419.  *----------------------------------------------------------------------
  2420.  */
  2421.  
  2422. void
  2423. Tcl_DStringEndSublist(dsPtr)
  2424.     Tcl_DString *dsPtr;            /* Dynamic string. */
  2425. {
  2426.     Tcl_DStringAppend(dsPtr, "}", -1);
  2427. }
  2428.  
  2429. /*
  2430.  *----------------------------------------------------------------------
  2431.  *
  2432.  * Tcl_PrintDouble --
  2433.  *
  2434.  *    Given a floating-point value, this procedure converts it to
  2435.  *    an ASCII string using.
  2436.  *
  2437.  * Results:
  2438.  *    The ASCII equivalent of "value" is written at "dst".  It is
  2439.  *    written using the current precision, and it is guaranteed to
  2440.  *    contain a decimal point or exponent, so that it looks like
  2441.  *    a floating-point value and not an integer.
  2442.  *
  2443.  * Side effects:
  2444.  *    None.
  2445.  *
  2446.  *----------------------------------------------------------------------
  2447.  */
  2448.  
  2449. void
  2450. Tcl_PrintDouble(interp, value, dst)
  2451.     Tcl_Interp *interp;            /* Interpreter whose tcl_precision
  2452.                      * variable used to be used to control
  2453.                      * printing.  It's ignored now. */
  2454.     double value;            /* Value to print as string. */
  2455.     char *dst;                /* Where to store converted value;
  2456.                      * must have at least TCL_DOUBLE_SPACE
  2457.                      * characters. */
  2458. {
  2459.     char *p;
  2460.  
  2461.     sprintf(dst, precisionFormat, value);
  2462.  
  2463.     /*
  2464.      * If the ASCII result looks like an integer, add ".0" so that it
  2465.      * doesn't look like an integer anymore.  This prevents floating-point
  2466.      * values from being converted to integers unintentionally.
  2467.      */
  2468.  
  2469.     for (p = dst; *p != 0; p++) {
  2470.     if ((*p == '.') || (isalpha(UCHAR(*p)))) {
  2471.         return;
  2472.     }
  2473.     }
  2474.     p[0] = '.';
  2475.     p[1] = '0';
  2476.     p[2] = 0;
  2477. }
  2478.  
  2479. /*
  2480.  *----------------------------------------------------------------------
  2481.  *
  2482.  * TclPrecTraceProc --
  2483.  *
  2484.  *    This procedure is invoked whenever the variable "tcl_precision"
  2485.  *    is written.
  2486.  *
  2487.  * Results:
  2488.  *    Returns NULL if all went well, or an error message if the
  2489.  *    new value for the variable doesn't make sense.
  2490.  *
  2491.  * Side effects:
  2492.  *    If the new value doesn't make sense then this procedure
  2493.  *    undoes the effect of the variable modification.  Otherwise
  2494.  *    it modifies the format string that's used by Tcl_PrintDouble.
  2495.  *
  2496.  *----------------------------------------------------------------------
  2497.  */
  2498.  
  2499.     /* ARGSUSED */
  2500. char *
  2501. TclPrecTraceProc(clientData, interp, name1, name2, flags)
  2502.     ClientData clientData;    /* Not used. */
  2503.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2504.     char *name1;        /* Name of variable. */
  2505.     char *name2;        /* Second part of variable name. */
  2506.     int flags;            /* Information about what happened. */
  2507. {
  2508.     char *value, *end;
  2509.     int prec;
  2510.  
  2511.     /*
  2512.      * If the variable is unset, then recreate the trace.
  2513.      */
  2514.  
  2515.     if (flags & TCL_TRACE_UNSETS) {
  2516.     if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
  2517.         Tcl_TraceVar2(interp, name1, name2,
  2518.             TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES
  2519.             |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData);
  2520.     }
  2521.     return (char *) NULL;
  2522.     }
  2523.  
  2524.     /*
  2525.      * When the variable is read, reset its value from our shared
  2526.      * value.  This is needed in case the variable was modified in
  2527.      * some other interpreter so that this interpreter's value is
  2528.      * out of date.
  2529.      */
  2530.  
  2531.     if (flags & TCL_TRACE_READS) {
  2532.     Tcl_SetVar2(interp, name1, name2, precisionString,
  2533.         flags & TCL_GLOBAL_ONLY);
  2534.     return (char *) NULL;
  2535.     }
  2536.  
  2537.     /*
  2538.      * The variable is being written.  Check the new value and disallow
  2539.      * it if it isn't reasonable or if this is a safe interpreter (we
  2540.      * don't want safe interpreters messing up the precision of other
  2541.      * interpreters).
  2542.      */
  2543.  
  2544.     if (Tcl_IsSafe(interp)) {
  2545.     Tcl_SetVar2(interp, name1, name2, precisionString,
  2546.         flags & TCL_GLOBAL_ONLY);
  2547.     return "can't modify precision from a safe interpreter";
  2548.     }
  2549.     value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
  2550.     if (value == NULL) {
  2551.     value = "";
  2552.     }
  2553.     prec = strtoul(value, &end, 10);
  2554.     if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
  2555.         (end == value) || (*end != 0)) {
  2556.     Tcl_SetVar2(interp, name1, name2, precisionString,
  2557.         flags & TCL_GLOBAL_ONLY);
  2558.     return "improper value for precision";
  2559.     }
  2560.     TclFormatInt(precisionString, prec);
  2561.     sprintf(precisionFormat, "%%.%dg", prec);
  2562.     return (char *) NULL;
  2563. }
  2564.  
  2565. /*
  2566.  *----------------------------------------------------------------------
  2567.  *
  2568.  * TclNeedSpace --
  2569.  *
  2570.  *    This procedure checks to see whether it is appropriate to
  2571.  *    add a space before appending a new list element to an
  2572.  *    existing string.
  2573.  *
  2574.  * Results:
  2575.  *    The return value is 1 if a space is appropriate, 0 otherwise.
  2576.  *
  2577.  * Side effects:
  2578.  *    None.
  2579.  *
  2580.  *----------------------------------------------------------------------
  2581.  */
  2582.  
  2583. int
  2584. TclNeedSpace(start, end)
  2585.     char *start;        /* First character in string. */
  2586.     char *end;            /* End of string (place where space will
  2587.                  * be added, if appropriate). */
  2588. {
  2589.     /*
  2590.      * A space is needed unless either
  2591.      * (a) we're at the start of the string, or
  2592.      * (b) the trailing characters of the string consist of one or more
  2593.      *     open curly braces preceded by a space or extending back to
  2594.      *     the beginning of the string.
  2595.      * (c) the trailing characters of the string consist of a space
  2596.      *       preceded by a character other than backslash.
  2597.      */
  2598.  
  2599.     if (end == start) {
  2600.     return 0;
  2601.     }
  2602.     end--;
  2603.     if (*end != '{') {
  2604.     if (isspace(UCHAR(*end)) && ((end == start) || (end[-1] != '\\'))) {
  2605.         return 0;
  2606.     }
  2607.     return 1;
  2608.     }
  2609.     do {
  2610.     if (end == start) {
  2611.         return 0;
  2612.     }
  2613.     end--;
  2614.     } while (*end == '{');
  2615.     if (isspace(UCHAR(*end))) {
  2616.     return 0;
  2617.     }
  2618.     return 1;
  2619. }
  2620.  
  2621. /*
  2622.  *----------------------------------------------------------------------
  2623.  *
  2624.  * TclFormatInt --
  2625.  *
  2626.  *    This procedure formats an integer into a sequence of decimal digit
  2627.  *    characters in a buffer. If the integer is negative, a minus sign is
  2628.  *    inserted at the start of the buffer. A null character is inserted at
  2629.  *    the end of the formatted characters. It is the caller's
  2630.  *    responsibility to ensure that enough storage is available. This
  2631.  *    procedure has the effect of sprintf(buffer, "%d", n) but is faster.
  2632.  *
  2633.  * Results:
  2634.  *    An integer representing the number of characters formatted, not
  2635.  *    including the terminating \0.
  2636.  *
  2637.  * Side effects:
  2638.  *    The formatted characters are written into the storage pointer to
  2639.  *    by the "buffer" argument.
  2640.  *
  2641.  *----------------------------------------------------------------------
  2642.  */
  2643.  
  2644. int
  2645. TclFormatInt(buffer, n)
  2646.     char *buffer;        /* Points to the storage into which the
  2647.                  * formatted characters are written. */
  2648.     long n;            /* The integer to format. */
  2649. {
  2650.     long intVal;
  2651.     int i;
  2652.     int numFormatted, j;
  2653.     char *digits = "0123456789";
  2654.  
  2655.     /*
  2656.      * Check first whether "n" is the maximum negative value. This is
  2657.      * -2^(m-1) for an m-bit word, and has no positive equivalent;
  2658.      * negating it produces the same value.
  2659.      */
  2660.  
  2661.     if (n == -n) {
  2662.     sprintf(buffer, "%ld", n);
  2663.     return strlen(buffer);
  2664.     }
  2665.  
  2666.     /*
  2667.      * Generate the characters of the result backwards in the buffer.
  2668.      */
  2669.  
  2670.     intVal = (n < 0? -n : n);
  2671.     i = 0;
  2672.     buffer[0] = '\0';
  2673.     do {
  2674.     i++;
  2675.     buffer[i] = digits[intVal % 10];
  2676.     intVal = intVal/10;
  2677.     } while (intVal > 0);
  2678.     if (n < 0) {
  2679.     i++;
  2680.     buffer[i] = '-';
  2681.     }
  2682.     numFormatted = i;
  2683.  
  2684.     /*
  2685.      * Now reverse the characters.
  2686.      */
  2687.  
  2688.     for (j = 0;  j < i;  j++, i--) {
  2689.     char tmp = buffer[i];
  2690.     buffer[i] = buffer[j];
  2691.     buffer[j] = tmp;
  2692.     }
  2693.     return numFormatted;
  2694. }
  2695.  
  2696. /*
  2697.  *----------------------------------------------------------------------
  2698.  *
  2699.  * TclLooksLikeInt --
  2700.  *
  2701.  *    This procedure decides whether the leading characters of a
  2702.  *    string look like an integer or something else (such as a
  2703.  *    floating-point number or string).
  2704.  *
  2705.  * Results:
  2706.  *    The return value is 1 if the leading characters of p look
  2707.  *    like a valid Tcl integer.  If they look like a floating-point
  2708.  *    number (e.g. "e01" or "2.4"), or if they don't look like a
  2709.  *    number at all, then 0 is returned.
  2710.  *
  2711.  * Side effects:
  2712.  *    None.
  2713.  *
  2714.  *----------------------------------------------------------------------
  2715.  */
  2716.  
  2717. int
  2718. TclLooksLikeInt(p)
  2719.     char *p;            /* Pointer to string. */
  2720. {
  2721.     while (isspace(UCHAR(*p))) {
  2722.     p++;
  2723.     }
  2724.     if ((*p == '+') || (*p == '-')) {
  2725.     p++;
  2726.     }
  2727.     if (!isdigit(UCHAR(*p))) {
  2728.     return 0;
  2729.     }
  2730.     p++;
  2731.     while (isdigit(UCHAR(*p))) {
  2732.     p++;
  2733.     }
  2734.     if ((*p != '.') && (*p != 'e') && (*p != 'E')) {
  2735.     return 1;
  2736.     }
  2737.     return 0;
  2738. }
  2739.  
  2740. /*
  2741.  *----------------------------------------------------------------------
  2742.  *
  2743.  * TclGetIntForIndex --
  2744.  *
  2745.  *    This procedure returns an integer corresponding to the list index
  2746.  *    held in a Tcl object. The Tcl object's value is expected to be
  2747.  *    either an integer or the string "end". 
  2748.  *
  2749.  * Results:
  2750.  *    The return value is normally TCL_OK, which means that the index was
  2751.  *    successfully stored into the location referenced by "indexPtr".  If
  2752.  *    the Tcl object referenced by "objPtr" has the value "end", the
  2753.  *    value stored is "endValue". If "objPtr"s values is not "end" and
  2754.  *    can not be converted to an integer, TCL_ERROR is returned and, if
  2755.  *    "interp" is non-NULL, an error message is left in the interpreter's
  2756.  *    result object.
  2757.  *
  2758.  * Side effects:
  2759.  *    The object referenced by "objPtr" might be converted to an
  2760.  *    integer object.
  2761.  *
  2762.  *----------------------------------------------------------------------
  2763.  */
  2764.  
  2765. int
  2766. TclGetIntForIndex(interp, objPtr, endValue, indexPtr)
  2767.      Tcl_Interp *interp;    /* Interpreter to use for error reporting. 
  2768.                  * If NULL, then no error message is left
  2769.                  * after errors. */
  2770.      Tcl_Obj *objPtr;        /* Points to an object containing either
  2771.                  * "end" or an integer. */
  2772.      int endValue;        /* The value to be stored at "indexPtr" if
  2773.                  * "objPtr" holds "end". */
  2774.      int *indexPtr;        /* Location filled in with an integer
  2775.                  * representing an index. */
  2776. {
  2777.     Interp *iPtr = (Interp *) interp;
  2778.     char *bytes;
  2779.     int index, length, result;
  2780.  
  2781.     /*
  2782.      * THIS FAILS IF THE INDEX OBJECT'S STRING REP CONTAINS NULLS.
  2783.      */
  2784.     
  2785.     if (objPtr->typePtr == &tclIntType) {
  2786.     *indexPtr = (int)objPtr->internalRep.longValue;
  2787.     return TCL_OK;
  2788.     }
  2789.     
  2790.     bytes = TclGetStringFromObj(objPtr, &length);
  2791.     if ((*bytes == 'e')
  2792.         && (strncmp(bytes, "end", (unsigned) length) == 0)) {
  2793.     index = endValue;
  2794.     } else {
  2795.     result = Tcl_GetIntFromObj((Tcl_Interp *) NULL, objPtr, &index);
  2796.     if (result != TCL_OK) {
  2797.         if (iPtr != NULL) {
  2798.         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  2799.             "bad index \"", bytes,
  2800.             "\": must be integer or \"end\"", (char *) NULL);
  2801.         }
  2802.         return result;
  2803.     }
  2804.     }
  2805.     *indexPtr = index;
  2806.     return TCL_OK;
  2807. }
  2808.